package com.xliu.cs.openproject.lianliankan.view;

import com.xliu.cs.openproject.lianliankan.BarCode;
import com.xliu.cs.openproject.lianliankan.Config;
import com.xliu.cs.openproject.lianliankan.Coordinate;
import com.xliu.cs.openproject.lianliankan.PMModel;
import com.xliu.cs.openproject.lianliankan.music.MusicPlayer;
import com.xliu.cs.openproject.lianliankan.util.CommandUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;


public class PictureMatchingView implements ActionListener {
    private static final Logger LOG = LoggerFactory.getLogger(PictureMatchingView.class);
    /**
     * model
     */
    private final PMModel model;
    /**
     * frame
     */
    private final JFrame frame;
    /**
     * outer panel
     */
    private final JPanel centerJPanel;

    /**
     * prev image position
     **/
    private Coordinate prev = null;
    /**
     * the number of pictures in each line, square
     */
    private final AtomicInteger level = new AtomicInteger(4);
    /**
     * the original border, default red
     */
    private final Border border = BorderFactory.createLineBorder(Color.red, 2, true);
    /**
     * the clicked border, default green
     */
    private final Border clickedBorder = BorderFactory.createLineBorder(Color.green, 2, true);
    /**
     * the previous clicked panel
     */
    private PicturePanel prevPanel;

    private final Config config = Config.getInstance();

    private final String backPictureName = config.getBgImagePath();

    private boolean finishGame = false;
    private final MusicPlayer musicPlayer;
    // current music file path, can be a directory.
    private File musicPath = new File(config.getMusicPath());

    public PictureMatchingView(PMModel pmodel, int width, int height) {
        model = pmodel;
        frame = new JFrame();

        centerJPanel = new JPanel() {
            public void paintComponent(Graphics g) {
                super.paintComponent(g);
                ImageIcon img = new ImageIcon(backPictureName);
                g.drawImage(img.getImage(), 0, 0, null);
            }
        };

        // menu bar
        JMenuBar menuBar = new JMenuBar();
        menuBar.add(constructOptionsMenu());
        menuBar.add(constructMusicChooseMenu());
        menuBar.add(constructLinksMenu());
        menuBar.add(constructAboutMenu());

        frame.setJMenuBar(menuBar);

        frame.setLayout(new BorderLayout());
        frame.add(centerJPanel, BorderLayout.CENTER);
        frame.setTitle(config.getTitle());
        frame.setSize(width, height);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // start the music
        musicPlayer = MusicPlayer.getInstance();
        musicPlayer.play(musicPath);
    }

    private JMenu constructLinksMenu() {
        JMenu htmlMenu = new JMenu("链接");
        List<Config.Link> links = config.getLinks();
        for (Config.Link link : links) {
            JMenuItem cartoonHtmlMenu = new JMenuItem(link.getName());
            htmlMenu.add(cartoonHtmlMenu);
            cartoonHtmlMenu.addActionListener(e -> {
                if (finishGame) {
                    try {
                        CommandUtil.openUriLink(link.getSite());
                    } catch (IOException e1) {
                        JOptionPane.showMessageDialog(null, "原因: " + e1.getMessage(), "链接打开失败", JOptionPane.ERROR_MESSAGE);
                    }
                } else {
                    JOptionPane.showMessageDialog(null, config.getUnfinishedMsg(), "提示", JOptionPane.INFORMATION_MESSAGE);
                }
            });
        }
        return htmlMenu;
    }

    private JMenu constructAboutMenu() {
        JMenu aboutMenu = new JMenu("关于");
        Config.About about = config.getAbout();
        aboutMenu.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                JOptionPane.showMessageDialog(null, about.getMessage(), about.getTitle(), JOptionPane.INFORMATION_MESSAGE);
            }
        });
        return aboutMenu;
    }

    private JMenu constructMusicChooseMenu() {
        JMenu musicChooseMenu = new JMenu("音乐");
        musicChooseMenu.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                JFileChooser jfc = new JFileChooser(musicPath);
                jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
                int result = jfc.showDialog(new JLabel(), "选择");
                if (result == JFileChooser.APPROVE_OPTION) {
                    musicPath = jfc.getSelectedFile();
                    LOG.info("choose music path {}", musicPath.getAbsolutePath());
                    setMusicPath();
                }
            }
        });

        return musicChooseMenu;
    }

    private JMenu constructOptionsMenu() {
        JMenu setMenu = new JMenu("选项");
        JMenuItem lowLevelMenu = new JMenuItem("简易: 4 * 4");
        setMenu.add(lowLevelMenu);
        JMenuItem mediumLevelMenu = new JMenuItem("普通: 6 * 6");
        setMenu.add(mediumLevelMenu);
        JMenuItem highLevelMenu = new JMenuItem("困难: 8 * 8");
        setMenu.add(highLevelMenu);
        JMenuItem musicSuspendMenu = new JMenuItem("暂停音乐");
        setMenu.add(musicSuspendMenu);
        JMenuItem musicResumeMenu = new JMenuItem("继续音乐");
        setMenu.add(musicResumeMenu);

        lowLevelMenu.addActionListener(e -> setLevel(4));
        mediumLevelMenu.addActionListener(e -> setLevel(6));
        highLevelMenu.addActionListener(e -> setLevel(8));
        musicSuspendMenu.addActionListener(e -> musicPlayer.suspendCurrentMusic());
        musicResumeMenu.addActionListener(e -> musicPlayer.resumeCurrentMusic());

        JMenuItem restartMenu = new JMenuItem("重新开始");
        setMenu.add(restartMenu);
        restartMenu.addActionListener(e -> restart());

        return setMenu;
    }

    /***
     * the action of the click event
     * @param actionEvent : contains the coordinator of the clicked panel
     */
    public void actionPerformed(ActionEvent actionEvent) {
        LOG.debug("performed action {}", actionEvent.getActionCommand());

        PicturePanel jp = (PicturePanel) actionEvent.getSource();
        Coordinate pos = Coordinate.toCoordinate(actionEvent.getActionCommand());
        /*
         * current image position
         */
        Coordinate current;
        if (prev == null) {
            prev = pos;
            prevPanel = jp;
            jp.setBorder(clickedBorder);
            return;
        } else {
            current = pos;
            jp.setBorder(clickedBorder);
        }
        // draw the eliminating animation, currently just stop 0.1 secs
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            LOG.warn("interrupt sleep", e);
        }
        //if prev and current image is the same image, remove
        String[][] positions = model.getPosBelong();
        if (!prev.equals(current) && Objects.equals(positions[prev.getX()][prev.getY()], positions[current.getX()][current.getY()])) {
            String path = model.existPath(prev, current);
            if (path != null) {
                //repaint
                model.setBlock(prev, 0);
                model.setBlock(current, 0);
                if (model.getRemainNumber() == 0) {
                    gameOver();
                    prev = null;
                    return;
                }
            }

        }
        jp.setBorder(border);
        prevPanel.setBorder(border);
        prev = null;
    }

    public void show() {
        int numbers = level.get();
        int gap = 4;

        int width = frame.getWidth() - gap * numbers - 100;
        int height = frame.getHeight() - gap * numbers - 100;
        int rowSize = width / numbers;
        int colSize = height / numbers;
        model.readImages(numbers, numbers, rowSize, colSize);

        PicturePanel[][] panels = model.getPicturePanels();
        GridLayout gridLayout = new GridLayout(numbers, numbers);
        gridLayout.setHgap(gap);
        gridLayout.setVgap(gap);
        centerJPanel.setLayout(gridLayout);
        for (int i = 0; i < numbers; i++) {
            for (int j = 0; j < numbers; j++) {
                panels[i][j].setBorder(border);
                centerJPanel.add(panels[i][j]);
            }
        }

        frame.setVisible(true);

        model.addActionListener(this);
    }

    private void setLevel(int value) {
        level.set(value);
        restart();
    }

    private void gameOver() {
        //level += 2;

        centerJPanel.removeAll();
        model.removeActionListener(this);

        JOptionPane.showMessageDialog(null, "真厉害！点击图片验证二维码哦~_~", "爱情宣言(验证有惊喜)", JOptionPane.INFORMATION_MESSAGE);

        centerJPanel.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                //弹出二维码
                Config.BarCode barCode = config.getBarCode();
                final String paintContents = barCode.getContent();
                BufferedImage bImg = BarCode.encode(paintContents, 300, 300, barCode.getIconPath());

                JOptionPane.showMessageDialog(null, null, "扫描二维码", JOptionPane.INFORMATION_MESSAGE, new ImageIcon(bImg));

                int n = JOptionPane.showConfirmDialog(null, barCode.getCheckMsg(), "提示", JOptionPane.YES_NO_OPTION);
                while (n == 0) {
                    String result = JOptionPane.showInputDialog(null, "输入", "验证", JOptionPane.INFORMATION_MESSAGE);

                    if (!paintContents.equals(result)) {
                        JOptionPane.showMessageDialog(null, barCode.getCheckFailedMsg(), "验证失败", JOptionPane.ERROR_MESSAGE);
                    } else {
                        finishGame = true;
                        JOptionPane.showMessageDialog(null, barCode.getCheckSuccMsg(), "验证成功", JOptionPane.INFORMATION_MESSAGE);
                        break;
                    }
                    n = JOptionPane.showConfirmDialog(null, barCode.getCheckMsg(), "提示", JOptionPane.YES_NO_OPTION);
                }
            }
        });

    }

    private void restart() {
        centerJPanel.removeAll();
        if (centerJPanel.getMouseListeners().length != 0) {
            centerJPanel.removeMouseListener(centerJPanel.getMouseListeners()[0]);
        }
        model.removeActionListener(this);
        show();
        centerJPanel.repaint();
        finishGame = false;
    }

    private void setMusicPath() {
        musicPlayer.setMusicPathAndReplay(musicPath);
    }
}

